//
//  PlSUpdateUI.m
//  PlugSuit
//
//  Created by ∞ on 20/12/07.
//  Copyright 2007 Emanuele Vulcano (infinite-labs.net). All rights reserved.
//

#import "PlSUpdateUI.h"
#import "PlSUpdateInfo.h"
#import "NSAlert+L0Alert.h"

@interface PlSUpdateUI ()

- (NSInvocation*) _showNoticeAndDoInvocationWithDelegate:(id) delegate selector:(SEL) selector result:(PlSUpdateResult) result context:(void*) context;
- (void) _interpretResult:(PlSUpdateResult) result;

@end

@implementation PlSUpdateUI

@synthesize applicationBundle = _appBundle, locale = _locale, displayNoticeIfNoUpdate = _displayNoticeIfNoUpdate, activateBeforeShowingAlerts = _activateBeforeShowingAlerts;

- (id) init {
	if (![super init]) return nil;
	
	[self setApplicationBundleAndLocale:[NSBundle mainBundle]];
	return self;
}

- (void) dealloc {
	self.applicationBundle = nil;
	self.locale = nil;
	
	[super dealloc];
}

- (void) setApplicationBundleAndLocale:(NSBundle*) bundle {
	self.applicationBundle = bundle;
	self.locale = [[[NSLocale alloc] initWithLocaleIdentifier:[[self.applicationBundle preferredLocalizations] objectAtIndex:0]] autorelease];
}

- (void) _didPerformSynchronousCheckWithResult:(PlSUpdateResult) result {
	_lastResult = result;
}

- (NSInvocation*) _showNoticeAndDoInvocationWithDelegate:(id) delegate selector:(SEL) selector result:(PlSUpdateResult) result context:(void*) context {
	L0Log(@"scheduling invocation for = %@, selector = %@, result = %@", delegate, NSStringFromSelector(selector), PlSStringFromUpdateResult(result));
	if (self.displayNoticeIfNoUpdate) {
		if (result == kPlSUpdateResultNotNeeded) {
			NSAlert* a = [NSAlert alertNamed:@"PlSNoUpdateAvailable" inBundle:self.applicationBundle];
			if (self.activateBeforeShowingAlerts) [NSApp activateIgnoringOtherApps:YES];
			[a runModal];
		} else if (result == kPlSUpdateResultNotAvailable) {
			NSAlert* a = [NSAlert alertNamed:@"PlSInternetDown" inBundle:self.applicationBundle];
			if (self.activateBeforeShowingAlerts) [NSApp activateIgnoringOtherApps:YES];
			[a runModal];
		}
	}
	
	if (![delegate respondsToSelector:selector]) return nil;
	NSMethodSignature* sign = [delegate methodSignatureForSelector:selector];
	NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sign];
	[invo setTarget:delegate];
	[invo setSelector:selector];
	[invo setArgument:&self atIndex:2];
	[invo setArgument:&result atIndex:3];
	[invo setArgument:&context atIndex:4];
	
	[invo performSelector:@selector(invoke) withObject:nil afterDelay:0.001];
	return invo;
}

- (void) beginCheckForAppUpdateModalForWindow:(NSWindow*) window delegate:(id) delegate didEndSelector:(SEL) didEnd context:(void*) context {
	NSURL* url = [NSURL URLWithString:[self.applicationBundle objectForInfoDictionaryKey:@"PlSUpdateURL"]];
	double version = [[self.applicationBundle objectForInfoDictionaryKey:@"CFBundleVersion"] doubleValue];
	
	L0Log(@"application check at url = %@", url);
	
	PlSUpdateInfo* info = [[[PlSUpdateInfo alloc] initWithContentsOfURL:url] autorelease];
	if (!info) {
		if (delegate)
			[self _showNoticeAndDoInvocationWithDelegate:delegate selector:didEnd result:kPlSUpdateResultNotAvailable context:context];
		return;
	}
	
	if (version >= info.newVersion) {
		if (delegate)
			[self _showNoticeAndDoInvocationWithDelegate:delegate selector:didEnd result:kPlSUpdateResultNotNeeded context:context];
		return;
	}
	
	NSAlert* a = [NSAlert alertNamed:@"PlSUpdateAvailable" inBundle:self.applicationBundle];
	[a setMessageTextFormat:nil, info.newVersionString];
	[a setInformativeTextFormat:nil, info.newVersionString, [info preferredDescriptionForLocale:self.locale]];
	
	NSAssert(!_delegate, @"No pending calls on this object");
	_delegate = [delegate retain];
	_didEnd = didEnd;
	_info = [info retain];
	_context = context;

	if (window) {
		[self retain];
		[a beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(_didChoose:result:context:) contextInfo:NULL];
	} else {
		if (self.activateBeforeShowingAlerts) [NSApp activateIgnoringOtherApps:YES];
		[self _interpretResult:[a runModal]];
	}
}

- (void) _didChoose:(NSAlert*) a result:(NSInteger) result context:(void*) ctx {
	L0LogS(@"Checkpoint");

	[self _interpretResult:result];
	[self release];
}

- (void) _interpretResult:(NSInteger) result {
	L0LogS(@"Checkpoint");

	BOOL didGoToSite = YES;
	
	switch (result) {
		case NSAlertFirstButtonReturn: // download now
			[[NSWorkspace sharedWorkspace] openURL:_info.downloadURL];
			break;
			
		case NSAlertSecondButtonReturn: // cancel
			didGoToSite = NO;
			break;
			
		case NSAlertThirdButtonReturn: // more information
			[[NSWorkspace sharedWorkspace] openURL:_info.moreInfoURL];
			break;
	}
	
	[self _showNoticeAndDoInvocationWithDelegate:_delegate selector:_didEnd result:didGoToSite? kPlSUpdateResultAccept : kPlSUpdateResultCancel context:_context];
	[_delegate release]; _delegate = nil;
	[_info release]; _info = nil;
	_context = nil;
	_didEnd = nil;
}

- (void) beginCheckForUpdateForPlugIn:(PlSPlugIn*) pin modalForWindow:(NSWindow*) window delegate:(id) delegate didEndSelector:(SEL) didEnd context:(void*) context {

	NSURL* url = pin.updatesCheckURL;
	L0Log(@"plug-in = %@ check at url = %@", pin.identifier, url);

	id versionObj = [[NSBundle bundleWithPath:pin.userVisiblePath] objectForInfoDictionaryKey:@"CFBundleVersion"];
	
	if (!url || !versionObj) {
		[self _showNoticeAndDoInvocationWithDelegate:delegate selector:didEnd result:kPlSUpdateResultNotSupported context:context];
		return;
	}
	
	double version = [versionObj doubleValue];
	
	PlSUpdateInfo* info = [[[PlSUpdateInfo alloc] initWithContentsOfURL:url] autorelease];
	if (!info) {
		if (delegate)
			[self _showNoticeAndDoInvocationWithDelegate:delegate selector:didEnd result:kPlSUpdateResultNotAvailable context:context];
		return;
	}
	
	if (version >= info.newVersion) {
		if (delegate)
			[self _showNoticeAndDoInvocationWithDelegate:delegate selector:didEnd result:kPlSUpdateResultNotNeeded context:context];
		return;
	}
	
	NSAlert* a = [NSAlert alertNamed:@"PlSPlugInUpdateAvailable" inBundle:self.applicationBundle];
	[a setMessageTextFormat:nil, [[NSFileManager defaultManager] displayNameAtPath:pin.userVisiblePath], info.newVersionString];
	[a setInformativeTextFormat:nil, info.newVersionString, [info preferredDescriptionForLocale:self.locale]];
	
	NSAssert(!_delegate, @"No pending calls on this object");
	_delegate = [delegate retain];
	_didEnd = didEnd;
	_info = [info retain];
	_context = context;
	
	if (window) {
		[self retain];
		[a beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(_didChoose:result:context:) contextInfo:NULL];
	} else {
		if (self.activateBeforeShowingAlerts) [NSApp activateIgnoringOtherApps:YES];
		[self _interpretResult:[a runModal]];
	}
}

@end
